package morefun

//import org.apache.oro.text.regex.Pattern

import java.util.regex.Pattern
import java.net.{URLDecoder, URLEncoder}
import java.text.SimpleDateFormat
import java.util.Date

import scala.io.Source
import java.sql.{Connection, DriverManager, ResultSet};
/**
  * information container,like JavaBean
  */
case class NginxLogger(
                           var ip: String = "",
                           var time: String,
                           var deviceId: String,
                           var mac: String,
                           var channel: String,
                           var versionCode: String,
                           var timestamp: String,
                           var model: String,
                           var size: String = "",
                           var series: String,
                           var version: String,
                           var sn: String,
                           var manufacturer: String,
                           var brand: String,
                           var machine_type: String,
                           var machine_model: String,
                           var product_model: String,
                           var platform: String,
                           var mid: String,
                           var ext01: String,
                           var ext02: String,
                           var ext03: String) {

}

object NginxLogger {

  val line_test = """123.185.109.21 - - [24/Aug/2017:14:11:42 +0800] GET /bootstrap?model=75PUF7101&timestamp=1503555101948&nonceStr=f1k0t7&sign=6c121a6fc0098a3dca622e6ec3fb423ace721daa&versionCode=274&time=1503555101948&mac=14%3A3D%3AF2%3A1F%3A51%3AD2&channel=ddtv&deviceId=a882dc0eccfbdb9dbf23fbd4b9ccc129 HTTP/1.1" 200 0"""

  // 即系 Nginx Log 格式的正则
  val LOG_PATTERN = """(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})? (\S+) (\S+) (\[.+?\]) (\S+) (\S+)""".r

  // 获取所有参数的正则
  var PATTERN_PARAMS = """/bootstrap\?(\S+)""".r

  /**
    *
    * URL 解码
    * @param value
    * @return
    */
  def urlDecode(value : String): String = {
    URLDecoder.decode(value, "UTF8");
  }

  /**
    * 根据需求，将 Model 转换成 size 和 series
    * @param logger
    * @return
    */
  def doModel(logger: NginxLogger): NginxLogger = {
    // 如果已经设置了 size，则直接原样返回
    if (logger.size != null && !logger.size.isEmpty) {
      println("#-# NginxLogger::doModel already have size, logger.size  = " + logger.size );
    }else {

      if (logger.model != null && !logger.model.isEmpty) {
        try {
          val size = logger.model.substring(0,2);
          val series = logger.model.substring(5,9);
          logger.size = size;
          logger.series = series;
        }catch {
          case e: Exception => println("#-# NginxLogger::doModel exception, model = " +  logger.model);
        }finally {
          logger
        }
      }
    }

    // 返回最后的 logger
    logger;

  }

  def parseLogFile(filePath: String) {
    val file=Source.fromFile(filePath)
    for(line <- file.getLines)
    {
      try {
        var nginxLogger = parseLogLine(line);
        println("#-# NginxLogger::parseLogLine parseLogFile Logger = " + nginxLogger);
      }catch {
        case e: Exception => println("#-# NginxLogger::parseLogFile exception, model = " +  line);
      }
    }
    file.close
  }

  /**
    * 解析一行 Log，转换成 NginxLogger
    *
    * @param logLine
    * @return
    */
  def parseLogLine(logLine: String): NginxLogger = {

    println("#-# NginxLogger::parseLogLine - start parse - " + logLine);

    // 获取 Log 中的基本信息
    val res = LOG_PATTERN.findFirstMatchIn(logLine)

    if (res == null || res.isEmpty) {
      throw new RuntimeException("#-# NginxLogger::parseLogLine - Cannot parse log line: " + logLine)
    }

    val m = res.get;

    var ip = m.group(1); // 正则表达式中第一个是 IP
    var time = m.group(4).replace("[","").replace("]",""); // 获取时间
    var params = PATTERN_PARAMS.findFirstMatchIn(m.group(6)) // 获取所有的参数

    var mac = "";
    var versionCode = "";
    var timestamp = "";
    var channel = "";
    var deviceId = "";
    var model = "";
    var size = "";
    var series = "";
    var version = "";
    var sn = "";
    var manufacturer = "";
    var brand = "";
    var machine_type = "";
    var machine_model = "";
    var product_model = "";
    var platform = "";
    var mid = "";
    var ext01 = "";
    var ext02 = "";
    var ext03 = "";

    if (params.isEmpty) {
      throw new RuntimeException("Cannot parse log line: " + params)
    }


    val params2 = params.get;

    val paramsList = params2.toString().split("&");

//    println("paramsList size = " + paramsList.size);

    // 把第一个参数中的 URL 地址去掉
    if (paramsList.size >= 1) {
      paramsList(0) = paramsList(0).replace("/bootstrap?","");
    }

    //遍历所有参数，设置对应的变量
    for(i <- 1 to paramsList.size) {

      if (paramsList(i - 1).startsWith("mac=")) {
        mac = urlDecode(paramsList(i - 1).replace("mac=",""));
      }
      else if (paramsList(i - 1).startsWith("timestamp=")) {
        timestamp = urlDecode(paramsList(i - 1).replace("timestamp=",""));
      }
      else if (paramsList(i - 1).startsWith("versionCode=")) {
        versionCode = urlDecode(paramsList(i - 1).replace("versionCode=",""));
      }
      else if (paramsList(i - 1).startsWith("channel=")) {
        channel = urlDecode(paramsList(i - 1).replace("channel=",""));
      }
      else if (paramsList(i - 1).startsWith("deviceId=")) {
        deviceId = urlDecode(paramsList(i - 1).replace("deviceId=",""));
      }
      else if (paramsList(i - 1).startsWith("model=")) {
        model = urlDecode(paramsList(i - 1).replace("model=",""));
      }
      else if (paramsList(i - 1).startsWith("size=")) {
        size = urlDecode(paramsList(i - 1).replace("size=",""));
      }
      else if (paramsList(i - 1).startsWith("series=")) {
        series = urlDecode(paramsList(i - 1).replace("series=",""));
      }
      else if (paramsList(i - 1).startsWith("version=")) {
        version = urlDecode(paramsList(i - 1).replace("version=",""));
      }
      else if (paramsList(i - 1).startsWith("sn=")) {
        sn = urlDecode(paramsList(i - 1).replace("sn=",""));
      }
      else if (paramsList(i - 1).startsWith("manufacturer=")) {
        manufacturer = urlDecode(paramsList(i - 1).replace("manufacturer=",""));
      }
      else if (paramsList(i - 1).startsWith("brand=")) {
        brand = urlDecode(paramsList(i - 1).replace("brand=",""));
      }
      else if (paramsList(i - 1).startsWith("machine_type=")) {
        machine_type = urlDecode(paramsList(i - 1).replace("machine_type=",""));
      }
      else if (paramsList(i - 1).startsWith("machine_model=")) {
        machine_model = urlDecode(paramsList(i - 1).replace("machine_model=",""));
      }
      else if (paramsList(i - 1).startsWith("product_model=")) {
        product_model = urlDecode(paramsList(i - 1).replace("product_model=",""));
      }
      else if (paramsList(i - 1).startsWith("platform=")) {
        platform = urlDecode(paramsList(i - 1).replace("platform=",""));
      }
      else if (paramsList(i - 1).startsWith("mid=")) {
        mid = urlDecode(paramsList(i - 1).replace("mid=",""));
      }
      else if (paramsList(i - 1).startsWith("ext01=")) {
        ext01 = urlDecode(paramsList(i - 1).replace("ext01=",""));
      }
      else if (paramsList(i - 1).startsWith("ext02=")) {
        ext02 = urlDecode(paramsList(i - 1).replace("ext02=",""));
      }
      else if (paramsList(i - 1).startsWith("ext03=")) {
        ext03 = urlDecode(paramsList(i - 1).replace("ext03=",""));
      }

//      println("#-# NginxLogger::parseLogLine paramsList = " + paramsList(i-1));
    }

    // 生成 NgignxLogger 并且处理 model
    doModel(NginxLogger(ip, time, deviceId, mac, channel, versionCode, timestamp, model, size
        , series, version, sn, manufacturer, brand, machine_type, machine_model, product_model
        , platform, mid, ext01, ext02, ext03));
  }

  def nowDate(): String = {
    val now: Date = new Date()
    val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
    val date = dateFormat.format(now)
    return date
  }

  def main(args: Array[String]) {

    val startTime = (new Date()).getTime();

    println("#-# start = " + nowDate());
    parseLogFile("/Users/wdy/Downloads/feedbacktest_bootstrap.log");
//    parseLogFile("/Users/wdy/Downloads/daily.log.2017-08-10.log");
    val endTime = (new Date()).getTime();

    println("#-# end = " + nowDate());
    println("#-# duration = " + (endTime - startTime));

    // ----------
//    var nginxLogger = parseLogLine(line_test);
//    println(nginxLogger);

    // Change to Your Database Config
    val conn_str = "jdbc:mysql://114.55.2.82:3306/data_stat_test3?user=admin&password=W!nmess@2016"
    // Load the driver
    classOf[com.mysql.jdbc.Driver]
    // Setup the connection
    val conn = DriverManager.getConnection(conn_str)
    try {
//      // Configure to be Read Only
//      val statement = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)
//      // Execute Query
//      val rs = statement.executeQuery("SELECT * FROM daily_channel_stat ")
//      // Iterate Over ResultSet
//      while (rs.next) {
//        println(rs.getString("id"))
//        println(rs.getString("channel"))
//      }




        val sql = new StringBuilder()
          .append("INSERT INTO daily_channel_stat(channel,create_time,increament_count, active_count, total)")
          .append("     VALUES(?, ?, ?, ?, ?)")
        val pstm = conn.prepareStatement(sql.toString())
        pstm.setObject(1, "test2")
        pstm.setObject(2, "2017-08-20 00:00:00")
        pstm.setObject(3, "21")
        pstm.setObject(4, "33")
        pstm.setObject(5, "21")

      val rs2 = pstm.executeUpdate()
      //      val rs2 = statement.executeQuery("insert into daily_channel_stat " +
//        " (channel,create_time,increament_count, active_count, total) " +
//        " VALUES ('test2','2017-08-20 00:00:00','21','30','20');")

//      val rs2 = statement.executeQuery("update daily_channel_stat set " +
//        " channel = 'test2' " +
//        " where id = 1;")


      println(" 影响行数：" + rs2)

    } catch{
      case e:Exception =>e.printStackTrace
    }
    finally {
      conn.close
    }

  }
}
